package univer.oko.queryAnalizer.sqlEditor;


import univer.oko.queryAnalizer.sqlEditor.actions.FindAction;

import javax.swing.*;
import javax.swing.text.BadLocationException;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;

/**
 * Created by Sergey Kharlamov.
 * Date: 23.07.2006
 * Time: 12:00:11
 */
public class CDEditorPane extends JScrollPane {
    JTextPane editor;
    CDDocument doc;
    ArrayList<IEditorContentListener> listeners = new ArrayList<IEditorContentListener>();
    TextMiniTokenizer tokenizer;
    private boolean allowEditText;


    public CDEditorPane(boolean allowEditText) {
        this.allowEditText = allowEditText;
        doc = new CDDocument(CDEditorPane.this);
        editor = new JTextPane(doc);
        editor.setEditable(allowEditText);
        setViewportView(editor);
        InitTokenizer();
        initializeActions();

        if (allowEditText)
            editor.addKeyListener(new KeyListener() {
                public void keyTyped(KeyEvent e) {
                    fireTextChanged();
                }

                public void keyPressed(KeyEvent e) {
                    //To change body of implemented methods use File | Settings | File Templates.
                }

                public void keyReleased(KeyEvent e) {
                    //To change body of implemented methods use File | Settings | File Templates.
                }
            });

        //   editor.setActionMap(getActionsMap());
    }

    private void fireTextChanged() {
        for (IEditorContentListener listener : listeners) {
            listener.textChanged();
        }
    }

    public void addEditorContentListener(IEditorContentListener listener) {
        listeners.add(listener);
    }

    FindAction findAction;

    protected void initializeActions() {
//        undoAction = new UndoAction(this);
//        redoAction = new RedoAction(this);
//        cutAction = new CutAction(editor);
//        copyAction = new CopyAction(editor);
//        pasteAction = new PasteAction(editor);
        findAction = new FindAction(this);
//        findReplaceAction = new FindReplaceAction(this);
        //       findNextAction = new FindNextAction(this);
//        findPreviousAction = new FindPreviousAction(this);
    }

    /**
     * vyzov dialoga poiska i zameny
     */
    public void doFindAndReplace() {
        editor.requestFocus();

        //   boolean allowReplacement = isReplacementAllowed();
        String initSearchStr = editor.getSelectedText();
        FindAndReplaceDialog.showFindDialog(getTopLevelAncestor(), this, initSearchStr, true);

    }

    private void InitTokenizer() {
        tokenizer = new TextMiniTokenizer();
        for (int i = 0; i < EditorOptions.getCurrentEditorOptions().TOKENIZER_MSSQL_CATEGORY_COUNT; i++) {
            tokenizer.addTokenCategory(EditorOptions.getCurrentEditorOptions().TOKENIZER_CATEGORY_STRING_CONSTANTS[i],
                    EditorOptions.getCurrentEditorOptions().TOKENIZER_CATEGORY_NUMBER_CONSTANTS[i],
                    EditorOptions.getCurrentEditorOptions().TOKENIZER_CATEGORY_COMMENTS[i],
                    EditorOptions.getCurrentEditorOptions().TOKENIZER_CATEGORY_SPEC[i],
                    EditorOptions.getCurrentEditorOptions().TOKENIZER_CATEGORY_IDENTIFIER[i],
                    EditorOptions.getCurrentEditorOptions().TOKENIZER_CATEGORY_IDENTIFIER_SET[i]);
        }
    }

    public void setText(String text) {
        editor.setText(text);
        parseText();
        setDefaultStyles();
        formatText();
    }


    /**
     * Formatiruet sintaksis ukazannogo intervala teksta.
     * Predpolagaetsja, chto sintaksis uzhe razobran.
     *
     * @param beginPos
     * @param length
     */
    synchronized protected void formatText(int beginPos, int length) {
        if (tokenizer != null) {
            int left_index = tokenizer.findLeftInterval(beginPos);
            int right_index = tokenizer.findRightInterval(beginPos + length);

            if ((left_index == -2) ||
                    (left_index >= tokenizer.getIntervalCount()) ||
                    (right_index < 0))
                return;

            if (left_index < 0)
                left_index = 0;
            if (right_index >= tokenizer.getIntervalCount())
                right_index = tokenizer.getIntervalCount() - 1;

            for (int i = left_index; i <= right_index; i++) {
                TextInterval ti = tokenizer.getInterval(i);
                int curr_begin_pos = ti.getStartCharOffset();
                int curr_end_pos = ti.getNextCharOffset() - 1;
                if ((curr_begin_pos >= beginPos) && (beginPos <= curr_end_pos)) {
                    int category = tokenizer.getIntervalCategory(i);
                    setSyntaxAttributes(curr_begin_pos, ti.getLength(), category);
                }
            }
        }
    }

    /**
     * Formatiruet sintaksis vsego dokumenta.
     * Predpolagaetsja, chto sintaksis uzhe razobran.
     */
    protected void formatText() {
        if ((tokenizer != null) && (doc != null)) {
            for (int i = 0; i < tokenizer.getIntervalCount(); i++) {
                TextInterval ti = tokenizer.getInterval(i);
                int category = tokenizer.getIntervalCategory(i);
                setSyntaxAttributes(ti.getStartCharOffset(), ti.getLength(), category);
            }
        }
    }

    /**
     * Formatiruet tekst soglasno ukazannoj sintaksicheskoj kategorii.
     *
     * @param startPosition nachal'naja pozitsija intervala v tekste
     * @param length        dlina intervala
     * @param category      sintaksicheskaja kategorija intervala
     */
    protected void setSyntaxAttributes(int startPosition, int length, int category) {
        MutableAttributeSet attr = getSyntaxAttributeByCategory(category);

        if (attr != null)
            doc.setCharacterAttributes(startPosition, length, attr, false);
    }

    public String getText() {
        return editor.getText();
    }

    protected void parseText() {

        if ((tokenizer != null) && (doc != null)) {
            String txt = "";
            try {
                txt = doc.getText(0, doc.getLength());
            } catch (BadLocationException e) {
            }
            tokenizer.translateText(txt);
        }
    }

    /**
     * Vozvraschaet nabor atributov dlja ukazannoj kategorii tekuschego sintaksisa
     *
     * @param category
     * @return nabor atributov
     */
    protected MutableAttributeSet getSyntaxAttributeByCategory(int category) {
        int max_category = 0;
        max_category = EditorOptions.getCurrentEditorOptions().TOKENIZER_MSSQL_CATEGORY_COUNT - 1;


        if ((category < 0) || (category > max_category))
            return new SimpleAttributeSet();

        return EditorOptions.getCurrentEditorOptions().TOKENIZER_CATEGORY_STYLES[category];
    }

    /**
     * Ustanavlivaet umolchatel'nye stili na ves' dokument
     */
    protected void setDefaultStyles() {
        SimpleAttributeSet attr = new SimpleAttributeSet(EditorOptions.getCurrentEditorOptions().DEFAULT_PARAGRAPH_STYLE);
        StyleConstants.setLeftIndent(attr, 0);
        doc.setCharacterAttributes(0, doc.getLength() + 1, EditorOptions.getCurrentEditorOptions().DEFAULT_TEXT_STYLE, true);
        doc.setParagraphAttributes(0, doc.getLength() + 1, attr, true);

    }

    public ActionMap getActionsMap() {
        ActionMap actions = new ActionMap();

        findAction = new FindAction(this);
        actions.put(FindAction.TEXT, findAction);
        return actions;
    }

}
